const URL = {
  url: function () {
    var self = this
    var protocolPattern = /^([a-z0-9.+-]+:)/i,
      portPattern = /:[0-9]*$/,
      // Special case for a simple path URL
      simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,
      hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/,
      hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,
      hostnameMaxLen = 255
    var hostlessProtocol = {
        'javascript': true,
        'javascript:': true
      },
      unsafeProtocol = {
        'javascript': true,
        'javascript:': true
      },
      // RFC 2396: characters reserved for delimiting URLs.
      // We actually just auto-escape these.
      delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'],

      // RFC 2396: characters not allowed for various reasons.
      unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims),

      // Allowed by RFCs, but cause of XSS attacks.  Always escape these.
      autoEscape = ['\''].concat(unwise),
      // Characters that are never ever allowed in a hostname.
      // Note that any invalid chars are also handled, but these
      // are the ones that are *expected* to be seen, so we fast-path
      nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape),
      hostEndingChars = ['/', '?', '#'],
      slashedProtocol = {
        'http': true,
        'https': true,
        'ftp': true,
        'gopher': true,
        'file': true,
        'http:': true,
        'https:': true,
        'ftp:': true,
        'gopher:': true,
        'file:': true
      }

    self.URLs = self.URLs || {}
    return {
      parse: function (url, parseString, slashesDenoteHost) {
        if (typeof url !== 'string') {
          throw new TypeError('Parameter \'url\' must be a string, not ' + typeof url)
        }
        var URL = self.URLs
        var queryIndex = url.indexOf('?'),
          splitter = (queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#',
          uSplit = url.split(splitter),
          slashRegex = /\\/g
        uSplit[0] = uSplit[0].replace(slashRegex, '/')
        url = uSplit.join(splitter)
        var reset = url
        reset = reset.trim()
        if (!slashesDenoteHost && url.split('#').length === 1) {
          var simplePath = simplePathPattern.exec(reset)
          if (simplePath) {
            URL.path = reset
            URL.href = reset
            URL.pathname = simplePath[1]
            if (simplePath[2]) {
              URL.search = simplePath[2]
              if (parseString) {
                URL.query = self.queryString.decode(URL.search.substr(1))
              } else {
                this.query = URL.search.substr(1)
              }
            } else if (parseString) {
              URL.search = ''
              URL.query = {}
            } else {
              URL.search = ''
              URL.query = ''
            }
            return URL
          }
        }

        var proto = protocolPattern.exec(reset)
        // console.log(proto) ;
        if (proto) {
          proto = proto[0]
          var lowerProto = proto.toLowerCase()
          URL.protocol = lowerProto
          reset = reset.substr(proto.length)
        }
        if (slashesDenoteHost || proto || reset.match(/^\/\/[^@\/]+@[^@\/]+/)) {
          var slashes = reset.substr(0, 2) === '//'
          if (slashes && !(proto && hostlessProtocol[proto])) {
            reset = reset.substr(2)
            URL.slashes = true
          }
        }
        if (!hostlessProtocol[proto] && (slashes || (proto && !slashedProtocol[proto]))) {
          // there's a hostname.
          // the first instance of /, ?, ;, or # ends the host.
          //
          // If there is an @ in the hostname, then non-host chars *are* allowed
          // to the left of the last @ sign, unless some host-ending character
          // comes *before* the @-sign.
          // URLs are obnoxious.
          //
          // ex:
          // http://a@b@c/ => user:a@b host:c
          // http://a@b?@c => user:a host:c path:/?@c

          // v0.12 TODO(isaacs): This is not quite how Chrome does things.
          // Review our test case against browsers more comprehensively.
          // find the first instance of any hostEndingChars

          var hostEnd = -1
          for (var k = 0; k < hostEndingChars.length; k++) {
            var hec = reset.indexOf(hostEndingChars[k])
            if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {
              hostEnd = hec
            }
          }
          // at this point, either we have an explicit point where the
          // auth portion cannot go past, or the last @ char is the decider.
          var auth, atSign
          // console.log('------------' + hostEnd) ;
          if (hostEnd === -1) {
            atSign = reset.lastIndexOf('@')
          } else {
            // atSign must be in auth portion.
            // http://a@b/c@d => host:b auth:a path:/c@d
            atSign = reset.lastIndexOf('@', hostEnd)
          }
          // Now we have a portion which is definitely the auth.
          // Pull that off.
          if (atSign !== -1) {
            auth = reset.slice(0, atSign)
            reset = reset.slice(atSign + 1)
            URL.auth = decodeURIComponent(auth)
          }
          // the host is the remaining to the left of the first non-host char
          hostEnd = -1
          for (var j = 0; j < nonHostChars.length; j++) {
            var hec = reset.indexOf(nonHostChars[j])
            if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) {
              hostEnd = hec
            }
          }
          if (hostEnd === -1) {
            hostEnd = reset.length
          }
          URL.host = reset.slice(0, hostEnd)
          reset = reset.slice(hostEnd)

          var host = URL.host
          var port = portPattern.exec(host)
          if (port) {
            port = port[0]
            if (port !== ':') {
              URL.port = port.substr(1)
            }
            host = host.substr(0, host.length - port.length)
          }
          if (host) URL.hostname = host

          URL.hostname = URL.hostname || ''
          var ipv6Hostname = URL.hostname[0] === '[' &&
            URL.hostname[URL.hostname.length - 1] === ']'
          if (!ipv6Hostname) {
            var hostParts = URL.hostname.split(/\./)
            for (var i = 0, l = hostParts.length; i < l; i++) {
              var part = hostParts[i]
              if (!part) continue
              if (!part.match(hostnamePartPattern)) {
                var newPart = ''
                for (var j = 0, k = part.length; j < k; j++) {
                  if (part.charCodeAt(j) > 127) {
                    newPart += 'x'
                  } else {
                    newPart += part[j]
                  }
                }
                // we test again with ASCII char only
                if (!newPart.match(hostnamePartPattern)) {
                  var validParts = hostParts.slice(0, i)
                  var notHost = hostParts.slice((i + 1))
                  var bit = part.match(hostnamePartStart)
                  if (bit) {
                    validParts.push(bit[1])
                    notHost.unshift(bit[2])
                  }
                  if (notHost.length) {
                    reset = '/' + notHost.join('.') + reset
                  }
                  URL.hostname = validParts.join('.')
                  break
                }
              }
            }
          }

          if (URL.hostname.length > hostnameMaxLen) {
            URL.hostname = ''
          } else {
            URL.hostname = URL.hostname.toLowerCase()
          }

          // if(!ipv6Hostname){
          // URL.hostname =
          // }

          var p = URL.port ? ':' + URL.port : ''
          var h = URL.hostname || ''
          URL.host = h + p
          URL.href += URL.host

          if (ipv6Hostname) {
            URL.hostname = URL.hostname.substr(1, URL.hostname.length - 2)
            if (reset[0] !== '/') {
              reset = '/' + reset
            }
          }
        }

        if (!unsafeProtocol[lowerProto]) {
          for (var i = 0; i < autoEscape.length; i++) {
            var ae = autoEscape[i]
            if (reset.indexOf(ae) === -1) {
              continue
            }
            var esc = encodeURIComponent(ae)
            if (esc === ae) {
              esc = escape(ae)
            }
            reset = reset.split(ae).join(esc)
          }
        }

        var hash = reset.indexOf('#')
        if (hash !== -1) {
          URL.hash = hash
          reset = reset.slice(0, hash)
        }
        var qm = reset.indexOf('?')
        if (qm !== -1) {
          URL.search = reset.substr(qm)
          URL.query = reset.substr(qm + 1)
          if (parseString) {
            URL.query = self.queryString.decode(URL.query)
          }
          reset = reset.slice(0, qm)
        } else {
          URL.search = ''
          URL.query = {}
        }

        if (reset) URL.pathname = reset
        if (slashedProtocol[lowerProto] && URL.hostname && !URL.pathname) {
          URL.pathname = '/'
        }

        if (URL.pathname || URL.search) {
          var pp = URL.pathname || ''
          var ss = URL.search || ''
          URL.path = pp + ss
        }
        URL.href = this.format()
        return URL
      },
      format: function () {
        var URL = self.URLs
        // console.log('\n\n',URL,'\n\n') ;
        var auth = URL.auth || ''
        if (auth) {
          auth = encodeURIComponent(auth)
          auth = auth.replace(/%3A/i, ':')
          auth += '@'
        }
        var protocol = URL.protocol || '',
          pathname = URL.pathname || '',
          host = false,
          query = ''
        var hash = URL.hash || ''
        if (URL.host) {
          host = auth + URL.host
        } else if (URL.hostname) {
          host = auth + (URL.hostname.indexOf(':') === -1 ? URL.hostname : '[' + URL.hostname + ']')
          if (URL.port) {
            host += ':' + URL.port
          }
        }

        if (URL.query && (typeof URL.query === 'object') && Object.keys(URL.query).length) {
          query = self.queryString.encode(URL.query)
        }
        var search = URL.search || (query && ('?' + query)) || ''
        if (protocol && protocol.substr(-1) !== ':') protocol += ':'

        // only the slashedProtocols get the //.  Not mailto:, xmpp:, etc.
        // unless they had them to begin with.
        if (URL.slashes || (!protocol || slashedProtocol[protocol]) && host !== false) {
          host = '//' + (host || '')
          if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname
        } else if (!host) {
          host = ''
        }
        if (hash && hash.charAt(0) !== '#') hash = '#' + hash
        if (search && search.charAt(0) !== '?') search = '?' + search

        pathname = pathname.replace(/[?#]/g, function (match) {
          return encodeURIComponent(match)
        })

        // console.log(protocol,host ,pathname) ;

        search = search.replace('#', '%23')
        return protocol + host + pathname + search + hash
      }
    }
  },
  decode: function (qs, sep, eq, options) {
    'use strict'

    function hasOwnProperty (obj, prop) {
      return Object.prototype.hasOwnProperty.call(obj, prop)
    }

    console.log(qs, sep, eq, options)
    sep = sep || '&'
    eq = eq || '='
    var obj = {}

    if (typeof qs !== 'string' || qs.length === 0) {
      return obj
    }
    var regexp = /\+/g
    qs = qs.split(sep)
    var maxKeys = 1000
    if (options && typeof options.maxKeys === 'number') {
      maxKeys = options.maxKeys
    }
    var len = qs.length
    if (maxKeys > 0 && len > maxKeys) {
      len = maxKeys
    }
    for (var i = 0; i < len; i++) {
      var x = qs[i].replace(regexp, '%20'),
        idx = x.indexOf(eq),
        kStr, vStr, k, v
      if (idx >= 0) {
        kStr = x.substr(0, idx)
        vStr = x.substr(idx + 1)
      } else {
        kStr = x
        vStr = ''
      }

      k = decodeURIComponent(kStr)
      v = decodeURIComponent(vStr)

      if (!hasOwnProperty(obj, k)) {
        obj[k] = v
      } else if (Array.isArray(obj[k])) {
        obj[k].push(v)
      } else {
        obj[k] = [obj[k], v]
      }
    }
    return obj
  },
  encode: function (obj, sep, eq, name) {
    'use strict'
    var stringifyPrimitive = function (v) {
      switch (typeof (v)) {
        case 'string':
          return v
        case 'boolean':
          return v ? 'true' : 'false'
        case 'number':
          return isFinite(v) ? v : ''
        default:
          return ''
      }
    }

    sep = sep || '&'
    eq = eq || '='
    if (obj === null) {
      obj = undefined
    }

    if (typeof obj === 'object') {
      return Object.keys(obj).map(function (k) {
        var ks = encodeURIComponent(stringifyPrimitive(k)) + eq
        if (Array.isArray(obj[k])) {
          return obj[k].map(function (v) {
            return ks + encodeURIComponent(stringifyPrimitive(v))
          }).join(sep)
        } else {
          return ks + encodeURIComponent(stringifyPrimitive(obj[k]))
        }
      }).join(sep)
    }

    if (!name) return ''
    return encodeURIComponent(stringifyPrimitive(name)) + eq + encodeURIComponent(stringifyPrimitive(obj))
  },
  getUrlKey: function (_url, name) {
    return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(_url) || [, ''])[1].replace(/\+/g, '%20')) || null
  },
  getParams: function (_url) {
    var url = _url
    var obj = {}
    if (url.indexOf('?') > -1) {
      var str = url.split('?')[1]
      var strs = str.split('&')
      for (var i = 0; i < strs.length; i++) {
        obj[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1])
      }
    } else {
      obj = null
    }
    return obj
  }
}

export default URL
